using UnityEngine;
using System.Runtime.InteropServices;

public abstract class ObjectController : MonoBehaviour
{
    [StructLayout(LayoutKind.Explicit)]
    private struct ObjectValue32
    {
        [FieldOffset(0)]
        public int _s32;
        [FieldOffset(0)]
        public float _f32;
    }

    [StructLayout(LayoutKind.Explicit)]
    private struct ObjectValue64
    {
        [FieldOffset(0)]
        public long _s64;
        [FieldOffset(0)]
        public double _f64;
    }

    private readonly int[] m_objTypeFlags = new int[] {
	    (int)OBJECT_TYPE_FLAG.TYPE_OBJECT_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_LOCATABLEOBJECT_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_STATICOBJECT_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_AURAOBJECT_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_UNIT_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_CREATURE_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_PLAYER_FLAG,
        (int)OBJECT_TYPE_FLAG.TYPE_AUTOPLAYER_FLAG,
    };

    protected OBJECT_TYPE m_objType;
    protected ObjGUID m_guid;

    private ObjectValue32[] m_values32;
    private BitMask m_bitMast32;
    private ObjectValue64[] m_values64;
    private BitMask m_bitMast64;

    public OBJECT_TYPE GetObjType()
    {
        return m_objType;
    }
    public ObjGUID GetGuid()
    {
        return m_guid;
    }

    public bool IsType(OBJECT_TYPE objType)
    {
        return m_objType == objType;
    }
    public bool IsKindOf(OBJECT_TYPE objType)
    {
        return (m_objTypeFlags[(int)m_objType] &
            m_objTypeFlags[(int)objType]) == m_objTypeFlags[(int)objType];
    }

    public int GetS32Value(int index)
    {
        return m_values32[index]._s32;
    }
    public float GetF32Value(int index)
    {
        return m_values32[index]._f32;
    }

    public long GetS64Value(int index)
    {
        return m_values64[index]._s64;
    }
    public double GetF64Value(int index)
    {
        return m_values64[index]._f64;
    }

    public void Init(ObjGUID guid)
    {
        int values32Count = 0;
        int values64Count = 0;
        switch ((OBJECT_TYPE)guid.TID)
        {
            case OBJECT_TYPE.TYPE_STATICOBJECT:
                values32Count = (int)STATICOBJECT_PROPERTIES.SOBJ_END;
                values64Count = (int)STATICOBJECT64_PROPERTIES.SOBJ64_END;
                break;
            case OBJECT_TYPE.TYPE_AURAOBJECT:
                values32Count = (int)AURAOBJECT_PROPERTIES.AOBJ_END;
                values64Count = (int)AURAOBJECT64_PROPERTIES.AOBJ64_END;
                break;
            case OBJECT_TYPE.TYPE_CREATURE:
                values32Count = (int)CREATURE_PROPERTIES.CREATURE_END;
                values64Count = (int)CREATURE64_PROPERTIES.CREATURE64_END;
                break;
            case OBJECT_TYPE.TYPE_PLAYER:
                values32Count = (int)PLAYER_PROPERTIES.PLAYER_END;
                values64Count = (int)PLAYER64_PROPERTIES.PLAYER64_END;
                break;
            case OBJECT_TYPE.TYPE_AUTOPLAYER:
                values32Count = (int)AUTOPLAYER_PROPERTIES.APC_END;
                values64Count = (int)AUTOPLAYER64_PROPERTIES.APC64_END;
                break;
        }
        m_values32 = new ObjectValue32[values32Count];
        m_bitMast32 = new BitMask(values32Count);
        m_values64 = new ObjectValue64[values64Count];
        m_bitMast64 = new BitMask(values64Count);
        m_objType = (OBJECT_TYPE)guid.TID;
        m_guid = guid;
    }

    public virtual void LoadFromCreatePacket(NetPacket pck)
    {
        for (int i = 0, n = m_bitMast32.Size(); i < n; ++i)
        {
            pck.Read(out m_values32[i]._s32);
        }
        for (int i = 0, n = m_bitMast64.Size(); i < n; ++i)
        {
            pck.Read(out m_values64[i]._s64);
        }
    }

    public void ReadValue32UpdatePacket(NetPacket pck)
    {
        m_bitMast32.Load(pck);
        int i = m_bitMast32.FindFirst();
        for (; i != -1; i = m_bitMast32.FindNext(i))
        {
            pck.Read(out m_values32[i]._s32);
        }
    }

    public void ReadValue64UpdatePacket(NetPacket pck)
    {
        m_bitMast64.Load(pck);
        int i = m_bitMast64.FindFirst();
        for (; i != -1; i = m_bitMast64.FindNext(i))
        {
            pck.Read(out m_values64[i]._s64);
        }
    }
}
